package cn.cosmosx.base.config.swagger;

import cn.cosmosx.base.config.props.GlobalConfig;
import cn.cosmosx.base.constant.GlobalConstant;
import cn.cosmosx.base.exception.PlatformException;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.*;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.Contact;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.service.Response;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Swagger3配置类
 * <p>
 * 如需创建多个Docket，仅需要指定不同的
 */
@Slf4j
@Configuration
@EnableOpenApi
public class Swagger3Configuration {

    /**
     * swagger3 扫描的controller
     */
    public final static String CONTROLLER_PACKAGE = "cn.cosmosx.controller";

    @Value("${server.port:8080}")
    private String port;

    @Value("${server.servlet.context-path:}")
    private String rootPath;
    /**
     * swagger全局配置
     */
    @Autowired
    private GlobalConfig globalConfig;

    @Bean
    public Docket common() {
        return createDocket("common", CONTROLLER_PACKAGE);
    }

    /**
     * 创建Docket
     *
     * @param groupName - 分组
     * @param packages  - 扫描包路径
     * @return
     */
    Docket createDocket(String groupName, String... packages) {
        Docket docket = new Docket(DocumentationType.OAS_30).enable(globalConfig.getSwagger().isEnable())
                .apiInfo(new ApiInfoBuilder().title("QuickSand")
                        .description("QuickSand - " + groupName).version("1.0")
                        .contact(new Contact("gengzhy", "https://cosmosx.cn", "gengzyy@gmail.com"))
                        .build())
                .groupName(groupName)
                .select()
                .apis(scanBasePackages(packages))
                .paths(PathSelectors.any())
                .build()
                .globalRequestParameters(globalRequestParameters())
                .globalResponses(HttpMethod.POST, responses())
                .globalResponses(HttpMethod.GET, responses()).pathMapping("/");
        if (globalConfig.getSwagger().isEnable()) {
            log.info("Swagger3: http://127.0.0.1:{}{}/doc.html", port, rootPath);
        }
        return docket;
    }

    /**
     * 多包扫描支持，扫描的包生成{@linkplain Predicate < RequestHandler >}
     *
     * @param basePackages - 扫描的包
     * @return
     */
    public static Predicate<RequestHandler> scanBasePackages(final String... basePackages) {
        if (basePackages == null || basePackages.length == 0) {
            throw new PlatformException("basePackages不能为空");
        }
        Predicate<RequestHandler> predicate = null;
        for (int i = basePackages.length - 1; i >= 0; i--) {
            String strBasePackage = basePackages[i];
            if (StrUtil.isNotBlank(strBasePackage)) {
                Predicate<RequestHandler> tempPredicate = RequestHandlerSelectors.basePackage(strBasePackage);
                predicate = predicate == null ? tempPredicate : predicate.or(tempPredicate);
            }
        }
        if (predicate == null) {
            throw new PlatformException("basePackage配置不正确");
        }
        return predicate;
    }

    /**
     * 构建响应状态码
     *
     * @return
     */
    private List<Response> responses() {
        List<Response> responses = new LinkedList<>();
        responses.add(new ResponseBuilder().code("S").description("响应成功").build());
        responses.add(new ResponseBuilder().code("E").description("非'S'即为响应失败").build());
        return responses;
    }


    /**
     * 自定义请求参数
     *
     * @return - list
     */
    private List<RequestParameter> globalRequestParameters() {
        List<RequestParameter> params = new ArrayList<>();
        if (!globalConfig.getSwagger().isEnable()) {
            return params;
        }
        List<GlobalConfig.Swagger.Param> configParams = globalConfig.getSwagger().getParams();
        // 没开启加密，则过滤掉加密请求头：EncryptToken
        if (!globalConfig.isEnableEncrypt()) {
            List<GlobalConfig.Swagger.Param> newList = configParams.stream()
                    .filter(p -> !StringUtils.equalsIgnoreCase(GlobalConstant.ENCRYPT_TOKEN, p.getName()))
                    .collect(Collectors.toList());
            configParams.clear();
            configParams.addAll(newList);
        }
        List<RequestParameter> finalParams = new ArrayList<>();
        configParams.forEach(param -> {
            RequestParameter parameter = new RequestParameterBuilder()
                    .name(param.getName())
                    .description(param.getDesc())
                    .required(param.isRequired())
                    .in(param.getParamType())
                    .required(param.isRequired())
                    .hidden(param.isHidden())
                    .build();
            finalParams.add(parameter);
        });
        return finalParams;
    }

}
